<?php

/**
 * Created by PhpStorm.
 * User: soosoogoo
 * Date: 4/14
 * Time: 17:28
 */

namespace Helper;

use Config\Overall\Settings;

class Common
{
    /**
     * 指定精度加法
     * @param $number
     * @param $feeRate
     * @param $isIncr
     * @return string
     * ------------------------------------------------------------
     */
    public static function getFeeRate($number, $feeRate, $isIncr = false)
    {
        $item = 10000;
        if ($isIncr) {
            $rate = ($item + $feeRate) / $item;
        } else {
            $rate = ($item - $feeRate) / $item;
        }

        return self::sbcmul($number, $rate);
    }

    /**
     * 指定精度乘法
     * @param $num1
     * @param $num2
     * @param int $scale
     * @return string
     * ------------------------------------------------------------
     */
    public static function sbcmul($num1, $num2, $scale = Settings::NUM_ACCURACY)
    {
        return bcmul($num1, $num2, $scale);
    }

    /**
     * @desc 数组转换
     * @param $data
     * @param $column
     * @param null $index_key
     * @return array
     */
    public static function array_column($data, $column, $index_key = null)
    {
        $result_arr = [];
        foreach ($data as $item) {
            if ($index_key) {
                $result_arr[$item[$index_key]] = $item[$column];
            } else {
                $result_arr[$item[$column]] = $item;
            }
        }

        return $result_arr;
    }

    /**
     * @desc 日期公共日志
     * @param $result
     * ------------------------------------------------------------
     */
    public static function log($result)
    {
        $fileName = LOG_PATH . '/' . date('Y-m-d') . ".log";
        file_put_contents($fileName, json_encode(json_encode($result)) . PHP_EOL, FILE_APPEND);
    }

    /**
     * 随机字符串
     * @param int $len
     * @return string
     */
    public static function randStr($len = 6)
    {
        $chars = '0123456789abcdefghijklmnopqrstuvwxyz'; // characters to build the password from
        $string = "";
        for ($i = $len; $i > 0; $i--) {
            $position = rand() % strlen($chars);
            $string .= substr($chars, $position, 1);
        }
        return $string;
    }

    /**
     * ------------------------------------------------------------------
     * 获取平均值
     * @param $array
     * @return float
     * @author soosoogoo
     * ------------------------------------------------------------------
     */
    public static function avgArray($array)
    {
        $total = '0';
        foreach ($array as $item) {
            $total = self::sbcadd($total, $item);
        }

        return self::sbcdiv($total, count($array));
    }

    /**
     * 指定精度加法
     * @param $num1
     * @param $num2
     * @param int $scale
     * @return string
     * ------------------------------------------------------------
     */
    public static function sbcadd($num1, $num2, $scale = Settings::NUM_ACCURACY)
    {
        return bcadd($num1, $num2, $scale);
    }

    /**
     * 指定精度除法
     * @param $num1
     * @param $num2
     * @param int $scale
     * @return string
     * ------------------------------------------------------------
     */
    public static function sbcdiv($num1, $num2, $scale = Settings::NUM_ACCURACY)
    {
        return bcdiv($num1, $num2, $scale);
    }

    /**
     * 随机一个数量(coinFrom)
     * @param string|float|int $min
     * @param string|float|int $max
     * @param array<string|float|int=>int> $weightScales
     * @param int $size
     * @return string $value
     */
    public static function getRandomCoinAmount($min, $max, $weightScales, $size = 10)
    {
        // turn to string
        $min = "" . $min;
        $max = "" . $max;

        $value = self::getValueViaWeight($weightScales);
        $scale = $value ?? $size;


        // in case the $min is larger than the $max
        $minNum = self::sbccomp($min, $max) < 0 ? $min : $max;
        $maxNum = self::sbccomp($min, $max) < 0 ? $max : $min;

        // random a number between the min and max
        $value = self::getRandomNumber($minNum, $maxNum, $scale);

        $value = self::interceptNumber($value, $scale);

        return $value;
    }

    /**
     * 依据权重随机对应数据
     * @param $weightScales
     * @return mixed|null
     */
    public static function getValueViaWeight($weightScales)
    {
        $value = null;

        // random a weight to get the defined scale value configured
        $weight = "0";
        $weightArray = [];

        if (!is_array($weightScales)) {
            return $value;
        }
        foreach ($weightScales as $weightScale => $weightBoundary) {
            $weight = self::sbcadd($weightBoundary, $weight);
            $weightArray[$weightScale] = $weight;
        }

        $weight = self::getRandomNumber(0, $weight);

        if (empty($weightArray)) {
            return $value;
        }
        foreach ($weightArray as $weightScale => $weightBoundary) {
            if (self::sbccomp($weight, $weightBoundary) <= 0) {
//                Log::log(["权重符合", $weight, "<", $weightBoundary]);
                $value = $weightScale;
                break;
            }
        }

//        Log::log(["权重随机:", $weight, $value, $weightArray]);

        return $value;
    }

    public static function getRandomNumber($minNum, $maxNum, $size = 10)
    {
        // random a number between the min and max
        if (function_exists('gmp_random_range')) {
            $value = gmp_random_range($minNum, $maxNum);
        } else {
            $value = self::sbcadd(
                $minNum,
                self::sbcmul(
                    mt_rand() / mt_getrandmax(),
                    self::sbcsub($maxNum, $minNum, $size),
                    $size
                )
                , $size
            );
        }

        return $value;
    }

    /**
     * 指定精度减法
     * @param $num1
     * @param $num2
     * @param int $scale
     * @return string
     * ------------------------------------------------------------
     */
    public static function sbcsub($num1, $num2, $scale = Settings::NUM_ACCURACY)
    {
        return bcsub($num1, $num2, $scale);
    }

    /**
     * 指定精度比较
     * @param $num1
     * @param $num2
     * @param int $scale
     * @return int
     * ------------------------------------------------------------
     */
    public static function sbccomp($num1, $num2, $scale = Settings::NUM_ACCURACY)
    {
        return bccomp($num1, $num2, $scale);
    }

    /**
     * 截取字符串到指定精度
     * @param $number
     * @param $digit
     * @author soosoogoo
     * @return int
     * ------------------------------------------------------------------
     */
    public static function interceptNumber($number, $digit)
    {
        return bcadd($number, "0", $digit);
    }

    public static function getRandomCoinPrice($min, $max, $size = 10)
    {
        // turn to string
        $min = "" . $min;
        $max = "" . $max;

        // in case the $min is larger than the $max
        $minNum = self::sbccomp($min, $max) < 0 ? $min : $max;
        $maxNum = self::sbccomp($min, $max) < 0 ? $max : $min;

        // random a number between the min and max
        $value = self::getRandomNumber($minNum, $maxNum, $size);

        return $value;
    }

    /**
     * 在给定的数值范围内，随机生成数值
     * @deprecated
     * @param $min
     * @param $max
     * @param int $type 类型，0 不用处理精度数据(比如价格)，1需要四舍五入（比如除btc/usdt、eth/usdt以外的交易对委托数量）
     * @param int $size
     * @return float
     */
    public static function getRandomNum($min, $max, $type = 0, $size = 10)
    {
        // 随机位数, 并且验证位数 位数|权重,位数|权重,位数|权重
        // 调整位数 interceptNumber 位数 min max
        // 随机 gmp_random_range

        $min = "" . $min;
        $max = "" . $max;

        if (is_string($min) || is_string($max)) {
            $minNum = self::sbccomp($min, $max) < 0 ? $min : $max;
            $maxNum = self::sbccomp($min, $max) < 0 ? $max : $min;

            $value = self::sbcadd(
                $minNum,
                self::sbcmul(
                    mt_rand() / mt_getrandmax(),
                    self::sbcsub($maxNum, $minNum, $size),
                    $size
                )
                , $size
            );


            return $value;

        } else {

            $minNum = min($min, $max);
            $maxNum = max($min, $max);

            $value = $minNum + mt_rand() / mt_getrandmax() * ($maxNum - $minNum);

            if ($type == 0) return round($value, $size);

            if ($type == 1) {
                $tmp = rand(1, 100);

                if ($tmp <= 20) {
                    $scale = 0;
                } else if ($tmp <= 40) {
                    $scale = 1;
                } else if ($tmp <= 60) {
                    $scale = 2;
                } else if ($tmp <= 80) {
                    $scale = 3;
                } else {
                    $scale = $size;
                }

                $val = round($value, $scale);

                if (self::sbccomp($val, 0) <= 0) {
                    $val = round($val, $size);
                }

                return $val;
            }
        }
    }

    /**
     * ------------------------------------------------------------------
     *                卖2 100.95-101.05
     *                卖1 100.87-100.95
     *                买1 99.85 - 99.91
     *                买2 99.75 - 99.81
     * @param $range
     * @param $baseNumber 100
     * @return array
     * @author soosoogoo
     * ------------------------------------------------------------------
     */
    public static function getRange($range, $baseNumber)
    {
        list($minPercent, $maxPercent) = $range;
        $minPrice = Common::sbcmul($baseNumber, Common::sbcdiv($minPercent, 100));
        $maxPrice = Common::sbcmul($baseNumber, Common::sbcdiv($maxPercent, 100));

        return [$minPrice, $maxPrice];
    }

    /**
     * 随机一个结束毫秒时间戳
     * @param $range array
     * @return int
     */
    public static function randEndTime($range)
    {
        list($start, $end) = $range;

        return Common::getMsSecond() + rand($start, $end);
    }

    /**
     * 获取当前时间毫秒时间戳
     * @return float
     */
    public static function getMsSecond()
    {
        list($usec, $sec) = explode(" ", microtime());
        $msec = round($usec * 1e3);
        $msTimestamp = $sec * 1e3 + $msec;

        return $msTimestamp;
    }

    /**
     * @param $range
     * @return float|int
     * ------------------------------------------------------------
     */
    public static function randMsTime($range)
    {
        list($start, $end) = $range;

        return Common::getMsSecond() + rand($start, $end);
    }

    /**
     * 指定精度加法
     * @param $number
     * @param $timidRate
     * @return string
     * ------------------------------------------------------------
     */
    public static function getTimid($number, $timidRate, $isIncr = false)
    {
        $item = 10000;
        if ($isIncr) {
            $rate = ($item - $timidRate) / $item + 1;
        } else {
            $rate = $timidRate / $item;
        }

        return self::sbcmul($number, $rate);
    }
}

